3 use MediaWiki\Block\BlockRestrictionStore
;
4 use MediaWiki\Block\Restriction\PageRestriction
;
5 use MediaWiki\Block\Restriction\NamespaceRestriction
;
6 use Wikimedia\TestingAccessWrapper
;
7 use Wikimedia\Rdbms\LoadBalancer
;
12 * @coversDefaultClass SpecialBlock
14 class SpecialBlockTest
extends SpecialPageTestBase
{
18 protected function newSpecialPage() {
19 return new SpecialBlock();
22 public function tearDown() {
28 * @covers ::getFormFields()
30 public function testGetFormFields() {
31 $this->setMwGlobals( [
32 'wgEnablePartialBlocks' => false,
33 'wgBlockAllowsUTEdit' => true,
35 $page = $this->newSpecialPage();
36 $wrappedPage = TestingAccessWrapper
::newFromObject( $page );
37 $fields = $wrappedPage->getFormFields();
38 $this->assertInternalType( 'array', $fields );
39 $this->assertArrayHasKey( 'Target', $fields );
40 $this->assertArrayHasKey( 'Expiry', $fields );
41 $this->assertArrayHasKey( 'Reason', $fields );
42 $this->assertArrayHasKey( 'CreateAccount', $fields );
43 $this->assertArrayHasKey( 'DisableUTEdit', $fields );
44 $this->assertArrayHasKey( 'AutoBlock', $fields );
45 $this->assertArrayHasKey( 'HardBlock', $fields );
46 $this->assertArrayHasKey( 'PreviousTarget', $fields );
47 $this->assertArrayHasKey( 'Confirm', $fields );
49 $this->assertArrayNotHasKey( 'EditingRestriction', $fields );
50 $this->assertArrayNotHasKey( 'PageRestrictions', $fields );
51 $this->assertArrayNotHasKey( 'NamespaceRestrictions', $fields );
55 * @covers ::getFormFields()
57 public function testGetFormFieldsPartialBlocks() {
58 $this->setMwGlobals( [
59 'wgEnablePartialBlocks' => true,
61 $page = $this->newSpecialPage();
62 $wrappedPage = TestingAccessWrapper
::newFromObject( $page );
63 $fields = $wrappedPage->getFormFields();
65 $this->assertArrayHasKey( 'EditingRestriction', $fields );
66 $this->assertArrayHasKey( 'PageRestrictions', $fields );
67 $this->assertArrayHasKey( 'NamespaceRestrictions', $fields );
71 * @covers ::maybeAlterFormDefaults()
73 public function testMaybeAlterFormDefaults() {
74 $this->setMwGlobals( [
75 'wgEnablePartialBlocks' => false,
76 'wgBlockAllowsUTEdit' => true,
79 $block = $this->insertBlock();
81 // Refresh the block from the database.
82 $block = Block
::newFromTarget( $block->getTarget() );
84 $page = $this->newSpecialPage();
86 $wrappedPage = TestingAccessWrapper
::newFromObject( $page );
87 $wrappedPage->target
= $block->getTarget();
88 $fields = $wrappedPage->getFormFields();
90 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
91 $this->assertSame( $block->isHardblock(), $fields['HardBlock']['default'] );
92 $this->assertSame( $block->isCreateAccountBlocked(), $fields['CreateAccount']['default'] );
93 $this->assertSame( $block->isAutoblocking(), $fields['AutoBlock']['default'] );
94 $this->assertSame( !$block->isUsertalkEditAllowed(), $fields['DisableUTEdit']['default'] );
95 $this->assertSame( $block->getReason(), $fields['Reason']['default'] );
96 $this->assertSame( 'infinite', $fields['Expiry']['default'] );
100 * @covers ::maybeAlterFormDefaults()
102 public function testMaybeAlterFormDefaultsPartial() {
103 $this->setMwGlobals( [
104 'wgEnablePartialBlocks' => true,
107 $badActor = $this->getTestUser()->getUser();
108 $sysop = $this->getTestSysop()->getUser();
109 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
110 $pageMars = $this->getExistingTestPage( 'Mars' );
112 $block = new \
Block( [
113 'address' => $badActor->getName(),
114 'user' => $badActor->getId(),
115 'by' => $sysop->getId(),
116 'expiry' => 'infinity',
118 'enableAutoblock' => true,
121 $block->setRestrictions( [
122 new PageRestriction( 0, $pageSaturn->getId() ),
123 new PageRestriction( 0, $pageMars->getId() ),
124 new NamespaceRestriction( 0, NS_TALK
),
126 new PageRestriction( 0, 999999 ),
131 // Refresh the block from the database.
132 $block = Block
::newFromTarget( $block->getTarget() );
134 $page = $this->newSpecialPage();
136 $wrappedPage = TestingAccessWrapper
::newFromObject( $page );
137 $wrappedPage->target
= $block->getTarget();
138 $fields = $wrappedPage->getFormFields();
141 $pageMars->getTitle()->getPrefixedText(),
142 $pageSaturn->getTitle()->getPrefixedText(),
145 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
146 $this->assertSame( 'partial', $fields['EditingRestriction']['default'] );
147 $this->assertSame( implode( "\n", $titles ), $fields['PageRestrictions']['default'] );
151 * @covers ::processForm()
153 public function testProcessForm() {
154 $this->setMwGlobals( [
155 'wgEnablePartialBlocks' => false,
157 $badActor = $this->getTestUser()->getUser();
158 $context = RequestContext
::getMain();
160 $page = $this->newSpecialPage();
162 $expiry = 'infinity';
164 'Target' => (string)$badActor,
165 'Expiry' => 'infinity',
170 'CreateAccount' => '0',
171 'DisableUTEdit' => '0',
172 'DisableEmail' => '0',
178 $result = $page->processForm( $data, $context );
180 $this->assertTrue( $result );
182 $block = Block
::newFromTarget( $badActor );
183 $this->assertSame( $reason, $block->getReason() );
184 $this->assertSame( $expiry, $block->getExpiry() );
188 * @covers ::processForm()
190 public function testProcessFormExisting() {
191 $this->setMwGlobals( [
192 'wgEnablePartialBlocks' => false,
194 $badActor = $this->getTestUser()->getUser();
195 $sysop = $this->getTestSysop()->getUser();
196 $context = RequestContext
::getMain();
198 // Create a block that will be updated.
199 $block = new \
Block( [
200 'address' => $badActor->getName(),
201 'user' => $badActor->getId(),
202 'by' => $sysop->getId(),
203 'expiry' => 'infinity',
205 'enableAutoblock' => false,
209 $page = $this->newSpecialPage();
211 $expiry = 'infinity';
213 'Target' => (string)$badActor,
214 'Expiry' => 'infinity',
219 'CreateAccount' => '0',
220 'DisableUTEdit' => '0',
221 'DisableEmail' => '0',
227 $result = $page->processForm( $data, $context );
229 $this->assertTrue( $result );
231 $block = Block
::newFromTarget( $badActor );
232 $this->assertSame( $reason, $block->getReason() );
233 $this->assertSame( $expiry, $block->getExpiry() );
234 $this->assertSame( '1', $block->isAutoblocking() );
238 * @covers ::processForm()
240 public function testProcessFormRestrictions() {
241 $this->setMwGlobals( [
242 'wgEnablePartialBlocks' => true,
244 $badActor = $this->getTestUser()->getUser();
245 $context = RequestContext
::getMain();
247 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
248 $pageMars = $this->getExistingTestPage( 'Mars' );
251 $pageSaturn->getTitle()->getText(),
252 $pageMars->getTitle()->getText(),
255 $page = $this->newSpecialPage();
257 $expiry = 'infinity';
259 'Target' => (string)$badActor,
260 'Expiry' => 'infinity',
265 'CreateAccount' => '0',
266 'DisableUTEdit' => '0',
267 'DisableEmail' => '0',
272 'EditingRestriction' => 'partial',
273 'PageRestrictions' => implode( "\n", $titles ),
274 'NamespaceRestrictions' => '',
276 $result = $page->processForm( $data, $context );
278 $this->assertTrue( $result );
280 $block = Block
::newFromTarget( $badActor );
281 $this->assertSame( $reason, $block->getReason() );
282 $this->assertSame( $expiry, $block->getExpiry() );
283 $this->assertCount( 2, $block->getRestrictions() );
284 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
285 new PageRestriction( $block->getId(), $pageMars->getId() ),
286 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
291 * @covers ::processForm()
293 public function testProcessFormRestrictionsChange() {
294 $this->setMwGlobals( [
295 'wgEnablePartialBlocks' => true,
297 $badActor = $this->getTestUser()->getUser();
298 $context = RequestContext
::getMain();
300 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
301 $pageMars = $this->getExistingTestPage( 'Mars' );
304 $pageSaturn->getTitle()->getText(),
305 $pageMars->getTitle()->getText(),
308 // Create a partial block.
309 $page = $this->newSpecialPage();
311 $expiry = 'infinity';
313 'Target' => (string)$badActor,
314 'Expiry' => 'infinity',
319 'CreateAccount' => '0',
320 'DisableUTEdit' => '0',
321 'DisableEmail' => '0',
326 'EditingRestriction' => 'partial',
327 'PageRestrictions' => implode( "\n", $titles ),
328 'NamespaceRestrictions' => '',
330 $result = $page->processForm( $data, $context );
332 $this->assertTrue( $result );
334 $block = Block
::newFromTarget( $badActor );
335 $this->assertSame( $reason, $block->getReason() );
336 $this->assertSame( $expiry, $block->getExpiry() );
337 $this->assertFalse( $block->isSitewide() );
338 $this->assertCount( 2, $block->getRestrictions() );
339 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
340 new PageRestriction( $block->getId(), $pageMars->getId() ),
341 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
344 // Remove a page from the partial block.
345 $data['PageRestrictions'] = $pageMars->getTitle()->getText();
346 $result = $page->processForm( $data, $context );
348 $this->assertTrue( $result );
350 $block = Block
::newFromTarget( $badActor );
351 $this->assertSame( $reason, $block->getReason() );
352 $this->assertSame( $expiry, $block->getExpiry() );
353 $this->assertFalse( $block->isSitewide() );
354 $this->assertCount( 1, $block->getRestrictions() );
355 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
356 new PageRestriction( $block->getId(), $pageMars->getId() ),
359 // Remove the last page from the block.
360 $data['PageRestrictions'] = '';
361 $result = $page->processForm( $data, $context );
363 $this->assertTrue( $result );
365 $block = Block
::newFromTarget( $badActor );
366 $this->assertSame( $reason, $block->getReason() );
367 $this->assertSame( $expiry, $block->getExpiry() );
368 $this->assertFalse( $block->isSitewide() );
369 $this->assertCount( 0, $block->getRestrictions() );
371 // Change to sitewide.
372 $data['EditingRestriction'] = 'sitewide';
373 $result = $page->processForm( $data, $context );
375 $this->assertTrue( $result );
377 $block = Block
::newFromTarget( $badActor );
378 $this->assertSame( $reason, $block->getReason() );
379 $this->assertSame( $expiry, $block->getExpiry() );
380 $this->assertTrue( $block->isSitewide() );
381 $this->assertCount( 0, $block->getRestrictions() );
383 // Ensure that there are no restrictions where the blockId is 0.
384 $count = $this->db
->selectRowCount(
385 'ipblocks_restrictions',
387 [ 'ir_ipb_id' => 0 ],
390 $this->assertSame( 0, $count );
394 * @dataProvider provideCheckUnblockSelf
395 * @covers ::checkUnblockSelf
397 public function testCheckUnblockSelf(
405 $this->setMwGlobals( [
406 'wgBlockDisablesLogin' => false,
408 $this->setGroupPermissions( 'sysop', 'unblockself', true );
409 $this->setGroupPermissions( 'user', 'block', true );
410 // Getting errors about creating users in db in provider.
411 // Need to use mutable to ensure different named testusers.
413 'u1' => TestUserRegistry
::getMutableTestUser( __CLASS__
, 'sysop' )->getUser(),
414 'u2' => TestUserRegistry
::getMutableTestUser( __CLASS__
, 'sysop' )->getUser(),
415 'u3' => TestUserRegistry
::getMutableTestUser( __CLASS__
, 'sysop' )->getUser(),
416 'u4' => TestUserRegistry
::getMutableTestUser( __CLASS__
, 'sysop' )->getUser(),
417 'nonsysop' => $this->getTestUser()->getUser()
419 foreach ( [ 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget' ] as $var ) {
420 $
$var = $users[$
$var];
423 $block = new \
Block( [
424 'address' => $blockedUser->getName(),
425 'user' => $blockedUser->getId(),
426 'by' => $blockPerformer->getId(),
427 'expiry' => 'infinity',
429 'enableAutoblock' => true,
435 SpecialBlock
::checkUnblockSelf( $adjustTarget, $adjustPerformer ),
441 public function provideCheckUnblockSelf() {
442 // 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget'
444 [ 'u1', 'u2', 'u3', 'u4', true, 'Unrelated users' ],
445 [ 'u1', 'u2', 'u1', 'u4', 'ipbblocked', 'Block unrelated while blocked' ],
446 [ 'u1', 'u2', 'u1', 'u1', true, 'Has unblockself' ],
447 [ 'nonsysop', 'u2', 'nonsysop', 'nonsysop', 'ipbnounblockself', 'no unblockself' ],
448 [ 'nonsysop', 'nonsysop', 'nonsysop', 'nonsysop', true, 'no unblockself but can de-selfblock' ],
449 [ 'u1', 'u2', 'u1', 'u2', true, 'Can block user who blocked' ],
453 protected function insertBlock() {
454 $badActor = $this->getTestUser()->getUser();
455 $sysop = $this->getTestSysop()->getUser();
457 $block = new \
Block( [
458 'address' => $badActor->getName(),
459 'user' => $badActor->getId(),
460 'by' => $sysop->getId(),
461 'expiry' => 'infinity',
463 'enableAutoblock' => true,
471 protected function resetTables() {
472 $this->db
->delete( 'ipblocks', '*', __METHOD__
);
473 $this->db
->delete( 'ipblocks_restrictions', '*', __METHOD__
);
477 * Get a BlockRestrictionStore instance
479 * @return BlockRestrictionStore
481 private function getBlockRestrictionStore() : BlockRestrictionStore
{
482 $loadBalancer = $this->getMockBuilder( LoadBalancer
::class )
483 ->disableOriginalConstructor()
486 return new BlockRestrictionStore( $loadBalancer );